﻿using Grow.Db.Repository;
using Grow.EventBus.Cap.Enum;
using Grow.EventBus.Cap.PublisherEventData;
using Grow.EventBus.EventData;
using Grow.Json;
using Grow.Module.Service;
using Grow.Utils.Exceptions;
using System.Collections.Concurrent;

namespace Grow.EventBus.Cap.EventPublisher
{
    public class EventPublisher : IEventPublisher
    {
        private readonly ConcurrentBag<PublisherEventDataDto> _publisherEventDataDtos;
        private readonly IServiceContext _serviceContext;
        private readonly EventBusOptions _eventBusOptions;
        private readonly IJsonContext _jsonContext;
        private readonly IRepository<PublisherEventDataEntity> _publisherEventDataRepository;
        public EventPublisher(IServiceContext serviceContext)
        {
            _publisherEventDataDtos = new();
            _serviceContext = serviceContext;
            _eventBusOptions= _serviceContext.GetOptions<EventBusOptions>();
            _jsonContext = _serviceContext.GetRequiredService<IJsonContext>();
            _publisherEventDataRepository = _serviceContext.GetRequiredService<IRepository<PublisherEventDataEntity>>();
        }



        public async Task ExecuteAsync<TEventData>(Guid eventDataId, TEventData eventData, DateTimeOffset? delayAt = null, IDictionary<string, string>? eventHeaders = null, CancellationToken cancellationToken = default) where TEventData : IEventData
        {
            if (eventData is null)
            {
                throw new GrowCheckException($"eventDataId  {eventDataId} eventData is null");
            }
            var sendAt = DateTimeOffset.Now;
            var eventDataOptions = _serviceContext.GetOptions<EventDataOptions>(typeof(TEventData).FullName);
            eventHeaders ??= new Dictionary<string, string>();
            eventHeaders.Add(EventBusConsts.SendAtHeaderKey, sendAt.ToString());
            eventHeaders.Add(EventBusConsts.EventNameHeaderKey, eventDataOptions.EventName);
            eventHeaders.Add(EventBusConsts.EventDataIdHeaderKey, eventDataId.ToString());

            if (delayAt.HasValue)
            {
                if (delayAt.Value <= DateTimeOffset.Now)
                {
                    delayAt = null;
                }
                else
                {
                    eventHeaders.Add(EventBusConsts.DelayAtHeaderKey, delayAt.ToString() ?? "");
                }
            }
            var eventDataJson = _jsonContext.Serialize(eventData);
            if (eventDataJson is null)
            {
                throw new GrowCheckException($"eventDataId  {eventDataId} eventDataJson is null");
            }

            var eventHeadersJson = _jsonContext.Serialize(eventHeaders);
            if (eventHeadersJson is null)
            {
                throw new GrowCheckException($"eventDataId  {eventDataId} eventHeadersJson is null");
            }
            //数据库
            PublisherEventDataEntity publisherEventDataEntity = new(
                eventDataId,
                _eventBusOptions.EnvironmentName,
                eventDataOptions.EventName,
                eventDataJson,
                eventHeadersJson,
                EventDataStatusEnum.Wait,
                0,
                sendAt,
                delayAt,
                null,
                null);

            await _publisherEventDataRepository.AddAsync(publisherEventDataEntity, cancellationToken);

            PublisherEventDataDto publisherEventDataDto = new(eventDataId,
                 eventDataOptions.EventName,
                 eventDataJson,
                 eventHeadersJson,
                 sendAt,
                 delayAt
                 );

            _publisherEventDataDtos.Add(publisherEventDataDto);
        }



        public IEnumerable<PublisherEventDataDto> GetPublisherEventDatas()
        {
            return _publisherEventDataDtos;
        }
    }
}
